Background

This notebook is for preparing input files for pyclone-vi. The same files with a minor modification will be used as an input for FastClone.

Set up

suppressPackageStartupMessages({
  library(tidyverse)
  library(readxl)
  #library(cDriver) # Calculate CCF, https://github.com/hanasusak/cDriver/
})

Directories and File Inputs/Outputs

# Detect the ".git" folder -- this will be in the project root directory
# Use this as the root directory to ensure proper sourcing of functions 
# no matter where this is called from
root_dir <- rprojroot::find_root(rprojroot::has_dir(".git"))
analysis_dir <- file.path(root_dir, "analyses", "tumor-clone-inference")
input_dir <- file.path(analysis_dir, "input")
data_dir <- file.path(root_dir, "data")
files_dir <- file.path(root_dir, "analyses", "sample-distribution-analysis", "results")
maf_files_dir <- file.path(root_dir, "analyses", "tmb-vaf-longitudinal", "results")
#tmb_input_dir <- file.path(root_dir, "analyses", "tmb-vaf-longitudinal", "input")
#scratch_dir <- file.path(root_dir, "scratch")

# Input files
pbta_file <- file.path(files_dir, "pbta.tsv") # file from add-sample-distribution module
maf_file <- file.path(data_dir, "snv-consensus-plus-hotspots.maf.tsv.gz")
tmb_file <- file.path(maf_files_dir, "tmb_vaf_genomic.tsv")
genomic_paired_file <- file.path(files_dir, "genomic_assays_matched_time_points.tsv") # file from add-sample-distribution module
nautilus_dec_file <- file.path(input_dir, "deceased_samples.xlsx") 
palette_file <- file.path(root_dir, "figures", "palettes", "tumor_descriptor_color_palette.tsv")
#tmb_all_file <- file.path(tmb_input_dir, "snv-mutation-tmb-coding.tsv")


# EXAMPLE 
# But to replace with dir with cns data inferred by CNVkit
# PT_Z4BF2NSB_dir <- file.path(input_dir, "cnvkit_data_example/PT_Z4BF2NSB") 
cns_dir <- file.path(input_dir, "cnvkit_data") 

# File path to results directory
results_dir <-
  file.path(analysis_dir, "results")
if (!dir.exists(results_dir)) {
  dir.create(results_dir)
}

# File path to input directory
pyclonevi_input_dir <-
  file.path(analysis_dir, "results", "pyclone-vi-input")
if (!dir.exists(pyclonevi_input_dir)) {
  dir.create(pyclonevi_input_dir)
}

# File path to input directory
fastclone_input_dir <-
  file.path(analysis_dir, "results", "fastclone-input")
if (!dir.exists(pyclonevi_input_dir)) {
  dir.create(pyclonevi_input_dir)
}


# File path to plot directory
pyclone_plots_dir <-
  file.path(analysis_dir, "plots", "pyclone-vi")
if (!dir.exists(pyclone_plots_dir)) {
  dir.create(pyclone_plots_dir)
}


source(paste0(root_dir, "/figures/scripts/theme.R"))

Load and process data

# Let's count #specimens per sample 
# We will remove any samples with less than 2 specimens as phylogenies require at least 3 taxa
kids_specimens_n_df <- genomic_paired_df %>% 
  select(Kids_First_Participant_ID, Kids_First_Biospecimen_ID, tumor_descriptor) %>% 
  unique() %>% 
  dplyr::count(Kids_First_Participant_ID) %>% 
  dplyr::mutate(kids_specimens_n = glue::glue("{Kids_First_Participant_ID}  (N={n})")) %>%
  dplyr::rename(kids_specimens_number = n) %>% 
  filter(!kids_specimens_number <= 2) %>%

  left_join(genomic_paired_df, by = c("Kids_First_Participant_ID")) %>%
  #left_join(maf_df) %>% 
  filter(!is.na(Chromosome)) 


# Let's confirm and add the number of timepoints per sample
# In case we lost any from filtering hypermutants and high reads/alteration
timepoints_n_df <- kids_specimens_n_df %>% 
  select(Kids_First_Participant_ID, tumor_descriptor) %>% 
  unique() %>% 
  dplyr::count(Kids_First_Participant_ID) %>% 
  dplyr::mutate(kids_timepoints_n = glue::glue("{Kids_First_Participant_ID}  (N={n})")) %>%
  dplyr::rename(kids_timepoints_number = n) %>% 
  filter(!kids_timepoints_number <= 1)

df <- timepoints_n_df %>% 
  left_join(kids_specimens_n_df, by = c("Kids_First_Participant_ID")) %>% 
  write_tsv(file.path(results_dir, "samples_eligible_for_phylogeny.tsv"))

# Number of samples in the `genomic_paired_df` with > 3 biospecimens and >2 timepoints
samples_with_3bs <- print(length(unique(df$Kids_First_Participant_ID)))
[1] 34
samples_with_3bs <- print(unique(df$Kids_First_Participant_ID))
 [1] "PT_04V47WFC" "PT_0DWRY9ZX" "PT_19GCSK2S" "PT_1H2REHT2" "PT_23NZGSRJ" "PT_3KM9W8S8" "PT_75HRTX4S" "PT_8GN3TQRM" "PT_962TCBVR" "PT_99S5BPE3" "PT_9S6WMQ92"
[12] "PT_AQWDQW27" "PT_C1RDBCVM" "PT_CWXSP19D" "PT_D6AJHDST" "PT_DVXE38EX" "PT_EQX0VT4F" "PT_GTHZF21E" "PT_HFQNKP5X" "PT_HHG37M6W" "PT_HJMP6PH2" "PT_K8ZV7APT"
[23] "PT_KBFM551M" "PT_KTRJ8TFY" "PT_KZ56XHJT" "PT_MDWPRDBT" "PT_MNSEJCDM" "PT_N8W26H19" "PT_NJQ26FHN" "PT_NK8A49X5" "PT_S4YNE17X" "PT_TP6GS00H" "PT_Z4BF2NSB"
[34] "PT_ZZRBX5JT"
  
# List with samples eligible for phylogeny
# I added the information about to use for phylogenetic inferences
list_df <- df %>% 
  select(Kids_First_Participant_ID) %>% 
  unique() %>% 
  mutate(somatic_germline_phylogeny = case_when(grepl("PT_KZ56XHJT|PT_KTRJ8TFY", Kids_First_Participant_ID) ~ "yes",
                                        TRUE ~ "not_yet")) %>% 
  write_tsv(file.path(results_dir, "samples_eligible_for_phylogeny_list.tsv"))

# Remove large files
rm(genomic_paired_df, kids_specimens_n_df, tmb_df)

Add Nautilus location for Deceased specimens

nautilus_dec_df <- read_excel(nautilus_dec_file) %>% 
  right_join(df, by = c("sample_id", "aliquot_id", "tumor_descriptor")) %>%
  dplyr::mutate(mutation_id = paste(Kids_First_Participant_ID, tumor_descriptor, Kids_First_Biospecimen_ID, Chromosome, Start_Position, Reference_Allele, Tumor_Seq_Allele2, sep = ":")) #%>% 
  #write_tsv(file.path(results_dir, "nautilus_dec.tsv"))

list_df <- nautilus_dec_df %>% 
  select(Kids_First_Participant_ID, Kids_First_Biospecimen_ID, `Note field from Nautilus of initial parent`) %>% 
  unique() %>% 
  write_tsv(file.path(results_dir, "nautilus_dec_list.tsv"))

Other, maybe to delete


# Make list with samples with >2 biospecimens at Deceased timepoint
dec_n_df <- df %>% 
  filter(tumor_descriptor == "Deceased") %>% 
  select(Kids_First_Participant_ID, tumor_descriptor, Kids_First_Biospecimen_ID) %>% 
  unique() %>% 
  dplyr::count(Kids_First_Participant_ID) %>% 
 # dplyr::mutate(kids_dec_n = glue::glue("{Kids_First_Participant_ID}  (N={n})")) %>%
  dplyr::rename(kids_deceased_bs_number = n) %>% 
  filter(!kids_deceased_bs_number <= 1) %>% 
  write_tsv(file.path(results_dir, "kids_dec_multiple_bs_list.tsv"))

###-----------------------------------------------------
# let's look into PT_3KM9W8S8
#PT_3KM9W8S8_df <- nautilus_dec_df %>% 
#  filter(Kids_First_Participant_ID == "PT_3KM9W8S8",
 #        Kids_First_Biospecimen_ID == "BS_2NQXY528") %>% 
#  select(Kids_First_Participant_ID, Kids_First_Biospecimen_ID, `Note field from Nautilus of initial parent`) %>% 
#  unique() %>% 
#  write_tsv(file.path(results_dir, "nautilus_dec_list.tsv"))
  
#bs_id <- print(unique(PT_3KM9W8S8_df$Kids_First_Biospecimen_ID))

Create pyclone input files

We need to generate the input files according to the method’s template. Phylogenetic methods require at least 2 samples per tumor site (multiregional sampling per anatomical site). Here, we will consider kids samples with more than 2 timepoints with one or more biospecimens. We will compare later differences in samples with single vs multiple biospecimens.

# Create pyclone df for all samples
pyclone_all_samples_df <- nautilus_dec_df %>%
  select(Kids_First_Participant_ID, Kids_First_Biospecimen_ID, cg_id, 
         cg_id_kids, mutation_id, sample_id,
         tumor_descriptor, Chromosome, Start_Position, 
         Reference_Allele, Tumor_Seq_Allele2, t_ref_count, t_alt_count,
         normal_cn, tumor_fraction, mutation_count) %>% 
  
  # change names to match input requirements
  dplyr::rename("ref_counts" = "t_ref_count", 
                "alt_counts" = "t_alt_count",
                "tumour_content" = "tumor_fraction") %>%
  select(Kids_First_Participant_ID, Kids_First_Biospecimen_ID, tumor_descriptor, 
         cg_id_kids, mutation_id, sample_id, ref_counts, 
         alt_counts, normal_cn, tumour_content, mutation_count)

samples_pyclone <- print(unique(pyclone_all_samples_df$Kids_First_Participant_ID))
 [1] "PT_04V47WFC" "PT_0DWRY9ZX" "PT_19GCSK2S" "PT_1H2REHT2" "PT_23NZGSRJ" "PT_3KM9W8S8" "PT_75HRTX4S" "PT_8GN3TQRM" "PT_962TCBVR" "PT_99S5BPE3" "PT_9S6WMQ92"
[12] "PT_AQWDQW27" "PT_C1RDBCVM" "PT_CWXSP19D" "PT_D6AJHDST" "PT_DVXE38EX" "PT_EQX0VT4F" "PT_GTHZF21E" "PT_HFQNKP5X" "PT_HHG37M6W" "PT_HJMP6PH2" "PT_K8ZV7APT"
[23] "PT_KBFM551M" "PT_KTRJ8TFY" "PT_KZ56XHJT" "PT_MDWPRDBT" "PT_MNSEJCDM" "PT_N8W26H19" "PT_NJQ26FHN" "PT_NK8A49X5" "PT_S4YNE17X" "PT_TP6GS00H" "PT_Z4BF2NSB"
[34] "PT_ZZRBX5JT"
# Remove large files
# rm(nautilus_dec_df)

# I will test one HGG dataset for now
# PT_Z4BF2NSB

#PT_Z4BF2NSB_DF <- pyclone_all_samples_df %>% 
#  filter(Kids_First_Participant_ID == "PT_Z4BF2NSB")
                   

Add major_cn, minor_cn columns from cns files

# Save df with all data together
# We will need this to prepare the input fiel for ClonEvol
pyclone_input_all <- nautilus_dec_df %>%
  select(mutation_id, VAF, CCF, gene_protein, Hugo_Symbol) %>% 
  right_join(pyclone_input) %>% 
  write_tsv(file.path(results_dir, "pyclone_input_all_data.tsv"))
Joining with `by = join_by(mutation_id, Hugo_Symbol)`

Save input files

for (i in 1:length(data_dir) ) { 
  
  # Create sample_name
  sample_name <-  unique(as.character(gsub(".call.cns", "", str_split_fixed(data_dir[i], "/", 13)[,11])))
  #sample_name <-  unique(as.character(gsub(".call.cns", "", str_split_fixed(data_dir[i], "/", 10)[,9])))
  sample_name <- sort(sample_name, decreasing = FALSE)
  print(sample_name)
  
for (x in seq_along(sample_name) ) { 
  
  # Save input file for pyclone-vi
  pyclone_fname <- paste0(pyclonevi_input_dir, "/", sample_name[x], ".tsv")
  print(pyclone_fname)
  
  pyclone_input_subset <- pyclone_input %>%
    filter(Kids_First_Participant_ID == sample_name[x]) %>% 
    #select(-c(Kids_First_Participant_ID)) %>% 
  write_tsv(file.path(pyclone_fname))
  
  
  # Save input file for FastClone
  fastclone_fname <- paste0(fastclone_input_dir, "/", sample_name[x], ".tsv")
  print(fastclone_fname)
  
  fastclone_input_subset <- pyclone_input %>%
    dplyr::rename("var_counts" = "alt_counts") %>% 
    filter(Kids_First_Participant_ID == sample_name[x]) %>% 
    #select(-c(Kids_First_Participant_ID)) %>% 
  write_tsv(file.path(fastclone_fname))
  
  }
}
[1] "PT_KTRJ8TFY"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KTRJ8TFY.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KTRJ8TFY.tsv"
[1] "PT_KTRJ8TFY"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KTRJ8TFY.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KTRJ8TFY.tsv"
[1] "PT_KTRJ8TFY"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KTRJ8TFY.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KTRJ8TFY.tsv"
[1] "PT_KTRJ8TFY"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KTRJ8TFY.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KTRJ8TFY.tsv"
[1] "PT_KTRJ8TFY"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KTRJ8TFY.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KTRJ8TFY.tsv"
[1] "PT_KTRJ8TFY"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KTRJ8TFY.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KTRJ8TFY.tsv"
[1] "PT_KTRJ8TFY"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KTRJ8TFY.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KTRJ8TFY.tsv"
[1] "PT_KTRJ8TFY"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KTRJ8TFY.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KTRJ8TFY.tsv"
[1] "PT_KZ56XHJT"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KZ56XHJT.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KZ56XHJT.tsv"
[1] "PT_KZ56XHJT"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KZ56XHJT.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KZ56XHJT.tsv"
[1] "PT_KZ56XHJT"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KZ56XHJT.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KZ56XHJT.tsv"
[1] "PT_KZ56XHJT"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KZ56XHJT.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KZ56XHJT.tsv"
[1] "PT_KZ56XHJT"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KZ56XHJT.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KZ56XHJT.tsv"
[1] "PT_KZ56XHJT"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KZ56XHJT.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KZ56XHJT.tsv"
[1] "PT_KZ56XHJT"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KZ56XHJT.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KZ56XHJT.tsv"
[1] "PT_KZ56XHJT"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KZ56XHJT.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KZ56XHJT.tsv"
[1] "PT_KZ56XHJT"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KZ56XHJT.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KZ56XHJT.tsv"
[1] "PT_KZ56XHJT"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KZ56XHJT.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KZ56XHJT.tsv"
[1] "PT_KZ56XHJT"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KZ56XHJT.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KZ56XHJT.tsv"
[1] "PT_KZ56XHJT"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_KZ56XHJT.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_KZ56XHJT.tsv"
[1] "PT_Z4BF2NSB"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_Z4BF2NSB.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_Z4BF2NSB.tsv"
[1] "PT_Z4BF2NSB"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_Z4BF2NSB.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_Z4BF2NSB.tsv"
[1] "PT_Z4BF2NSB"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_Z4BF2NSB.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_Z4BF2NSB.tsv"
[1] "PT_Z4BF2NSB"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_Z4BF2NSB.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_Z4BF2NSB.tsv"
[1] "PT_Z4BF2NSB"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_Z4BF2NSB.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_Z4BF2NSB.tsv"
[1] "PT_Z4BF2NSB"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_Z4BF2NSB.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_Z4BF2NSB.tsv"
[1] "PT_Z4BF2NSB"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_Z4BF2NSB.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_Z4BF2NSB.tsv"
[1] "PT_Z4BF2NSB"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/pyclone-vi-input/PT_Z4BF2NSB.tsv"
[1] "/Users/chronia/CHOP/GitHub/pbta-tumor-evolution/analyses/tumor-clone-inference/results/fastclone-input/PT_Z4BF2NSB.tsv"

Plot depth coverage

# Read color palette
palette_df <- readr::read_tsv(palette_file, guess_max = 100000, show_col_types = FALSE) %>% 
  mutate(tumor_descriptor = color_names)

# Define and order palette
palette <- palette_df$hex_codes
names(palette) <- palette_df$tumor_descriptor

# Define timepoints
timepoints = c("Diagnosis", "Progressive", "Recurrence", "Deceased", "Second Malignancy", "Unavailable")
for (i in 1:length(data_dir) ) { 
  
  # Create sample_name
  sample_name <-  unique(as.character(gsub(".call.cns", "", str_split_fixed(data_dir[i], "/", 13)[,11])))
  sample_name <- sort(sample_name, decreasing = FALSE)
  print(sample_name)
  
for (x in seq_along(sample_name) ) { 
  
  pyclone_input_subset <- pyclone_input %>%
    filter(Kids_First_Participant_ID == sample_name[x]) %>% 
    select(-c(Kids_First_Participant_ID)) #%>% 
   # mutate(tumor_descriptor = factor(tumor_descriptor),
    #     tumor_descriptor = fct_relevel(tumor_descriptor, timepoints)) %>% 
    #arrange(tumor_descriptor, sample_id)
  
  # Make this reproducible
  set.seed(2023)

  # Define label for plots
  Timepoint <- factor(x = pyclone_input_subset$tumor_descriptor, levels = timepoints)
  
  #######################
  # Create bxp ref_counts
    p <- print(ggplot(pyclone_input_subset, aes(sample_id, ref_counts, color = Timepoint)) + 
                 geom_jitter(width = 0.15, size = 0.7, alpha = 0.6) +
                 ggplot2::geom_boxplot(color = "black",
                              size = 0.25,
                              alpha = 0,
                              coef = 0) + # remove whiskers
                 theme_Publication() + 
                 scale_color_manual(values = palette,
                                    breaks = sort(names(palette))) +
                 #rotate() +
                 theme(axis.text.x = element_text(angle = 90)) +
                 stat_summary(fun.y=mean,shape=1,col='black',geom='point') +
                 labs(title = sample_name[x],
                      x = "sample_id",
                      y = "ref_counts",
                      color = "Timepoint"))
    
    # Save the plot
    ggsave(filename = paste0(sample_name[x], "-ref_counts.pdf"), 
         path = pyclone_plots_dir, 
         width = 6, 
         height = 5, 
         device = "pdf", 
        useDingbats = FALSE)
    

  #######################
  # Create bxp alt_counts
    p <- print(ggplot(pyclone_input_subset, aes(sample_id, alt_counts, color = Timepoint)) + 
                 geom_jitter(width = 0.15, size = 0.7, alpha = 0.6) +
                 ggplot2::geom_boxplot(color = "black",
                              size = 0.25,
                              alpha = 0,
                              coef = 0) + # remove whiskers
                 theme_Publication() + 
                 scale_color_manual(values = palette,
                                    breaks = sort(names(palette))) +
                 #rotate() +
                 theme(axis.text.x = element_text(angle = 90)) +
                 stat_summary(fun.y=mean,shape=1,col='black',geom='point') +
                 labs(title = sample_name[x],
                      x = "sample_id",
                      y = "alt_counts",
                      color = "Timepoint"))
    
    # Save the plot
    ggsave(filename = paste0(sample_name[x], "-alt_counts.pdf"), 
         path = pyclone_plots_dir, 
         width = 6, 
         height = 5, 
         device = "pdf", 
        useDingbats = FALSE)
  
  
}
}
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"

Total number of mutations across timepoints and biospecimen sample per Patient case

for (i in 1:length(data_dir) ) { 
  
  # Create sample_name
  sample_name <-  unique(as.character(gsub(".call.cns", "", str_split_fixed(data_dir[i], "/", 13)[,11])))
  sample_name <- sort(sample_name, decreasing = FALSE)
  print(sample_name)
  
for (x in seq_along(sample_name) ) { 
  
  pyclone_input_subset <- pyclone_input %>%
    filter(Kids_First_Participant_ID == sample_name[x]) %>% 
    select(-c(Kids_First_Participant_ID))
  
  # Define parameters for function
  ylim = max(pyclone_input_subset$mutation_count)
  
  
   # Rename legend for timepoints
  Timepoint <- factor(pyclone_input_subset$tumor_descriptor)
  
  # Plot stacked barplot 
  print(ggplot(pyclone_input_subset, aes(x = sample_id, 
                                              y = mutation_count, 
                                              fill = Timepoint)) +  
               geom_col(position = position_stack(reverse = TRUE)) +
               geom_bar(stat = "identity", width = 0.5) + 
               scale_fill_manual(values = palette, breaks = sort(names(palette))) + 
               theme_Publication() + 
               theme(axis.text.x = element_text(angle = 85, 
                                                hjust = 1, 
                                                vjust = 1)) + 
               labs(title = paste(sample_name)) + 
               labs(x = "sample_id", y = "Total Mutations") +
               ylim(0, ylim)) 
  
  
}
}
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KTRJ8TFY"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_KZ56XHJT"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"
[1] "PT_Z4BF2NSB"

sessionInfo()
R version 4.3.1 (2023-06-16)
Platform: x86_64-apple-darwin20 (64-bit)
Running under: macOS Ventura 13.6.1

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.3-x86_64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: America/New_York
tzcode source: internal

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] ggthemes_4.2.4  readxl_1.4.3    lubridate_1.9.3 forcats_1.0.0   stringr_1.5.1   dplyr_1.1.4     purrr_1.0.2     readr_2.1.4     tidyr_1.3.0    
[10] tibble_3.2.1    ggplot2_3.4.4   tidyverse_2.0.0

loaded via a namespace (and not attached):
 [1] utf8_1.2.4        generics_0.1.3    stringi_1.8.1     hms_1.1.3         digest_0.6.33     magrittr_2.0.3    evaluate_0.23     timechange_0.2.0 
 [9] fastmap_1.1.1     cellranger_1.1.0  rprojroot_2.0.4   fansi_1.0.5       scales_1.2.1      clonevol_0.99.11  textshaping_0.3.7 cli_3.6.1        
[17] rlang_1.1.2       crayon_1.5.2      bit64_4.0.5       munsell_0.5.0     withr_2.5.2       yaml_2.3.7        tools_4.3.1       parallel_4.3.1   
[25] tzdb_0.4.0        colorspace_2.1-0  vctrs_0.6.4       R6_2.5.1          lifecycle_1.0.4   bit_4.0.5         vroom_1.6.4       ragg_1.2.6       
[33] pkgconfig_2.0.3   pillar_1.9.0      gtable_0.3.4      glue_1.6.2        systemfonts_1.0.5 xfun_0.41         tidyselect_1.2.0  rstudioapi_0.15.0
[41] knitr_1.45        farver_2.1.1      htmltools_0.5.7   rmarkdown_2.25    labeling_0.4.3    compiler_4.3.1   
LS0tCnRpdGxlOiAiSW5mZXJlbmNlIG9mIHN1YmNsb25hbCBhcmNoaXRlY3R1cmUgb2YgdHVtb3JzIGFjcm9zcyBtdWx0aXBsZSB0aW1lcG9pbnRzIGluIHRoZSBwYWlyZWQgbG9uZ2l0dWRpbmFsIChQTCkgY29ob3J0IgphdXRob3I6ICdBbnRvbmlhIENocm9uaSA8Y2hyb25pYUBjaG9wLmVkdT4gZm9yIEQzQicKZGF0ZTogIjIwMjMiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKLS0tCgojIEJhY2tncm91bmQKClRoaXMgbm90ZWJvb2sgaXMgZm9yIHByZXBhcmluZyBpbnB1dCBmaWxlcyBmb3IgW3B5Y2xvbmUtdmldKGh0dHBzOi8vZ2l0aHViLmNvbS9Sb3RoLUxhYi9weWNsb25lLXZpKS4gVGhlIHNhbWUgZmlsZXMgd2l0aCBhIG1pbm9yIG1vZGlmaWNhdGlvbiB3aWxsIGJlIHVzZWQgYXMgYW4gaW5wdXQgZm9yIFtGYXN0Q2xvbmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9HdWFuTGFiL0Zhc3RDbG9uZV9HdWFuTGFiKS4KCgojIFNldCB1cAoKYGBge3IgbG9hZC1saWJyYXJ5fQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoewogIGxpYnJhcnkodGlkeXZlcnNlKQogIGxpYnJhcnkocmVhZHhsKQogICNsaWJyYXJ5KGNEcml2ZXIpICMgQ2FsY3VsYXRlIENDRiwgaHR0cHM6Ly9naXRodWIuY29tL2hhbmFzdXNhay9jRHJpdmVyLwp9KQpgYGAKCiMgRGlyZWN0b3JpZXMgYW5kIEZpbGUgSW5wdXRzL091dHB1dHMKCmBgYHtyIHNldC1kaXItYW5kLWZpbGUtbmFtZXN9CiMgRGV0ZWN0IHRoZSAiLmdpdCIgZm9sZGVyIC0tIHRoaXMgd2lsbCBiZSBpbiB0aGUgcHJvamVjdCByb290IGRpcmVjdG9yeQojIFVzZSB0aGlzIGFzIHRoZSByb290IGRpcmVjdG9yeSB0byBlbnN1cmUgcHJvcGVyIHNvdXJjaW5nIG9mIGZ1bmN0aW9ucyAKIyBubyBtYXR0ZXIgd2hlcmUgdGhpcyBpcyBjYWxsZWQgZnJvbQpyb290X2RpciA8LSBycHJvanJvb3Q6OmZpbmRfcm9vdChycHJvanJvb3Q6Omhhc19kaXIoIi5naXQiKSkKYW5hbHlzaXNfZGlyIDwtIGZpbGUucGF0aChyb290X2RpciwgImFuYWx5c2VzIiwgInR1bW9yLWNsb25lLWluZmVyZW5jZSIpCmlucHV0X2RpciA8LSBmaWxlLnBhdGgoYW5hbHlzaXNfZGlyLCAiaW5wdXQiKQpkYXRhX2RpciA8LSBmaWxlLnBhdGgocm9vdF9kaXIsICJkYXRhIikKZmlsZXNfZGlyIDwtIGZpbGUucGF0aChyb290X2RpciwgImFuYWx5c2VzIiwgInNhbXBsZS1kaXN0cmlidXRpb24tYW5hbHlzaXMiLCAicmVzdWx0cyIpCm1hZl9maWxlc19kaXIgPC0gZmlsZS5wYXRoKHJvb3RfZGlyLCAiYW5hbHlzZXMiLCAidG1iLXZhZi1sb25naXR1ZGluYWwiLCAicmVzdWx0cyIpCiN0bWJfaW5wdXRfZGlyIDwtIGZpbGUucGF0aChyb290X2RpciwgImFuYWx5c2VzIiwgInRtYi12YWYtbG9uZ2l0dWRpbmFsIiwgImlucHV0IikKI3NjcmF0Y2hfZGlyIDwtIGZpbGUucGF0aChyb290X2RpciwgInNjcmF0Y2giKQoKIyBJbnB1dCBmaWxlcwpwYnRhX2ZpbGUgPC0gZmlsZS5wYXRoKGZpbGVzX2RpciwgInBidGEudHN2IikgIyBmaWxlIGZyb20gYWRkLXNhbXBsZS1kaXN0cmlidXRpb24gbW9kdWxlCm1hZl9maWxlIDwtIGZpbGUucGF0aChkYXRhX2RpciwgInNudi1jb25zZW5zdXMtcGx1cy1ob3RzcG90cy5tYWYudHN2Lmd6IikKdG1iX2ZpbGUgPC0gZmlsZS5wYXRoKG1hZl9maWxlc19kaXIsICJ0bWJfdmFmX2dlbm9taWMudHN2IikKZ2Vub21pY19wYWlyZWRfZmlsZSA8LSBmaWxlLnBhdGgoZmlsZXNfZGlyLCAiZ2Vub21pY19hc3NheXNfbWF0Y2hlZF90aW1lX3BvaW50cy50c3YiKSAjIGZpbGUgZnJvbSBhZGQtc2FtcGxlLWRpc3RyaWJ1dGlvbiBtb2R1bGUKbmF1dGlsdXNfZGVjX2ZpbGUgPC0gZmlsZS5wYXRoKGlucHV0X2RpciwgImRlY2Vhc2VkX3NhbXBsZXMueGxzeCIpIApwYWxldHRlX2ZpbGUgPC0gZmlsZS5wYXRoKHJvb3RfZGlyLCAiZmlndXJlcyIsICJwYWxldHRlcyIsICJ0dW1vcl9kZXNjcmlwdG9yX2NvbG9yX3BhbGV0dGUudHN2IikKI3RtYl9hbGxfZmlsZSA8LSBmaWxlLnBhdGgodG1iX2lucHV0X2RpciwgInNudi1tdXRhdGlvbi10bWItY29kaW5nLnRzdiIpCgoKIyBFWEFNUExFIAojIEJ1dCB0byByZXBsYWNlIHdpdGggZGlyIHdpdGggY25zIGRhdGEgaW5mZXJyZWQgYnkgQ05Wa2l0CiMgUFRfWjRCRjJOU0JfZGlyIDwtIGZpbGUucGF0aChpbnB1dF9kaXIsICJjbnZraXRfZGF0YV9leGFtcGxlL1BUX1o0QkYyTlNCIikgCmNuc19kaXIgPC0gZmlsZS5wYXRoKGlucHV0X2RpciwgImNudmtpdF9kYXRhIikgCgojIEZpbGUgcGF0aCB0byByZXN1bHRzIGRpcmVjdG9yeQpyZXN1bHRzX2RpciA8LQogIGZpbGUucGF0aChhbmFseXNpc19kaXIsICJyZXN1bHRzIikKaWYgKCFkaXIuZXhpc3RzKHJlc3VsdHNfZGlyKSkgewogIGRpci5jcmVhdGUocmVzdWx0c19kaXIpCn0KCiMgRmlsZSBwYXRoIHRvIGlucHV0IGRpcmVjdG9yeQpweWNsb25ldmlfaW5wdXRfZGlyIDwtCiAgZmlsZS5wYXRoKGFuYWx5c2lzX2RpciwgInJlc3VsdHMiLCAicHljbG9uZS12aS1pbnB1dCIpCmlmICghZGlyLmV4aXN0cyhweWNsb25ldmlfaW5wdXRfZGlyKSkgewogIGRpci5jcmVhdGUocHljbG9uZXZpX2lucHV0X2RpcikKfQoKIyBGaWxlIHBhdGggdG8gaW5wdXQgZGlyZWN0b3J5CmZhc3RjbG9uZV9pbnB1dF9kaXIgPC0KICBmaWxlLnBhdGgoYW5hbHlzaXNfZGlyLCAicmVzdWx0cyIsICJmYXN0Y2xvbmUtaW5wdXQiKQppZiAoIWRpci5leGlzdHMocHljbG9uZXZpX2lucHV0X2RpcikpIHsKICBkaXIuY3JlYXRlKHB5Y2xvbmV2aV9pbnB1dF9kaXIpCn0KCgojIEZpbGUgcGF0aCB0byBwbG90IGRpcmVjdG9yeQpweWNsb25lX3Bsb3RzX2RpciA8LQogIGZpbGUucGF0aChhbmFseXNpc19kaXIsICJwbG90cyIsICJweWNsb25lLXZpIikKaWYgKCFkaXIuZXhpc3RzKHB5Y2xvbmVfcGxvdHNfZGlyKSkgewogIGRpci5jcmVhdGUocHljbG9uZV9wbG90c19kaXIpCn0KCgpzb3VyY2UocGFzdGUwKHJvb3RfZGlyLCAiL2ZpZ3VyZXMvc2NyaXB0cy90aGVtZS5SIikpCmBgYAoKIyBMb2FkIGFuZCBwcm9jZXNzIGRhdGEKCmBgYHtyIGxvYWQtcHJvY2Vzcy1pbnB1dHN9CiMgUmVhZCBpbiBoaXN0b2xvZ2llcyBmaWxlIGFuZCBmaWx0ZXIgZm9yIHRoZSBwYnRhIGNvaG9ydApwYnRhIDwtIHJlYWRyOjpyZWFkX3RzdihwYnRhX2ZpbGUsIGd1ZXNzX21heCA9IDEwMDAwMCwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZmlsdGVyKCEoZXhwZXJpbWVudGFsX3N0cmF0ZWd5ID09ICJSTkEtU2VxIikpICU+JSAKICBzZWxlY3QoS2lkc19GaXJzdF9QYXJ0aWNpcGFudF9JRCwgS2lkc19GaXJzdF9CaW9zcGVjaW1lbl9JRCwgY2dfaWQsIHR1bW9yX2Rlc2NyaXB0b3IsCiAgICAgICAgIHNhbXBsZV9pZCwgYWxpcXVvdF9pZCwKICAgICAgICAgdHVtb3JfZnJhY3Rpb24sIHR1bW9yX3Bsb2lkeSkKCiMgUmVhZCBpbiB0bWJfYWxsIGZpbGUKdG1iX2RmIDwtIHJlYWRyOjpyZWFkX3Rzdih0bWJfZmlsZSwgZ3Vlc3NfbWF4ID0gMTAwMDAwLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAKCiMgUmVhZCBtYWYKIyBLZWVwIGJvdGggc3lub255bW91cyBhbmQgbm9uLXN5bm95bW91cyBtdXRhdGlvbnMgZm9yIHRoZSBjdXJyZW50IGFuYWx5c2lzCm1hZl9maWxlX2RmIDwtIHZyb29tOjp2cm9vbShtYWZfZmlsZSwgZGVsaW0gPSAiXHQiLCBjb2xfbmFtZXMgPSBUUlVFKQoKIyBNYWtlIGEgdmVjdG9yIG9mIGNvZGluZyBnZW5lIG11dGF0aW9ucwojbWFmX25vbnN5bm9ueW1vdXMgPC0gYygKIyAgIk1pc3NlbnNlX011dGF0aW9uIiwKIyAgIkZyYW1lX1NoaWZ0X0RlbCIsCiMgICJJbl9GcmFtZV9JbnMiLAojICAiRnJhbWVfU2hpZnRfSW5zIiwKIyAgIlNwbGljZV9TaXRlIiwKIyAgIk5vbnNlbnNlX011dGF0aW9uIiwKIyAgIkluX0ZyYW1lX0RlbCIsCiMgICJOb25zdG9wX011dGF0aW9uIiwKIyAgIlRyYW5zbGF0aW9uX1N0YXJ0X1NpdGUiCiMpCgojIFByb2Nlc3MgbWFmCm1hZl9kZiA8LSBtYWZfZmlsZV9kZiAlPiUKICBmaWx0ZXIoVHVtb3JfU2FtcGxlX0JhcmNvZGUgJWluJSBwYnRhJEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQjLAogICAgICAgICAjVmFyaWFudF9DbGFzc2lmaWNhdGlvbiAlaW4lIG1hZl9ub25zeW5vbnltb3VzCiAgICAgICAgICkgJT4lCiAgZHBseXI6OnJlbmFtZShLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lEID0gVHVtb3JfU2FtcGxlX0JhcmNvZGUpICU+JSAKICBsZWZ0X2pvaW4ocGJ0YSkgJT4lCiAgbGVmdF9qb2luKHRtYl9kZikgJT4lCgogICMgQ2FsY3VsYXRlIFZBRiAKICBkcGx5cjo6bXV0YXRlKFZBRiA9IHRfYWx0X2NvdW50IC8gKHRfcmVmX2NvdW50ICsgdF9hbHRfY291bnQpLCAKICAgICAgICAgICAgICAgICMgQ29uY2F0ZW5hdGUgZ2VuZSBhbmQgcHJvdGVpbiBpbmZvcm1hdGlvbgogICAgICAgICAgICAgICAgZ2VuZV9wcm90ZWluID0gcGFzdGUoSHVnb19TeW1ib2wsIEhHVlNwX1Nob3J0LCBzZXAgPSAiXyIpKSAlPiUgIAogIHNlbGVjdChLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lELCBLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lELCBjZ19pZCwgdHVtb3JfZGVzY3JpcHRvciwKICAgICAgICAgc2FtcGxlX2lkLCBhbGlxdW90X2lkLCBDaHJvbW9zb21lLCAKICAgICAgICAgU3RhcnRfUG9zaXRpb24sIFJlZmVyZW5jZV9BbGxlbGUsIFR1bW9yX1NlcV9BbGxlbGUxLCBUdW1vcl9TZXFfQWxsZWxlMiwKICAgICAgICAgdF9yZWZfY291bnQsIHRfYWx0X2NvdW50LCAKICAgICAgICAgdHVtb3JfZnJhY3Rpb24sIHR1bW9yX3Bsb2lkeSwgVkFGLCBnZW5lX3Byb3RlaW4sIEh1Z29fU3ltYm9sLAogICAgICAgICBtdXRhdGlvbl9jb3VudCwgdG1iKSAlPiUgCgogICMgUmVtb3ZlIGh5cGVybXV0YW50cwogIGZpbHRlcighdG1iID49IDEwICMsIAogIAogICMgVGhlcmUgYXJlIGFsdGVyYXRpb25zIHdpdGggaGlnaCBudW1iZXIgb2YgcmVhZCBjb3VudHMuCiAgIyBXZSB3aWxsIGV4Y2x1ZGUgdGhvc2Ugd2l0aCA+MTAwMCBmb3Igbm93LgogICAgICAgICMgIXRfYWx0X2NvdW50ID49IDEwMDAsCiAgICAgICAgICMhdF9yZWZfY291bnQgPj0gMTAwMAogICkgICU+JSAKICAKICAjIEFkZCBgbm9ybWFsX2NuYDogVG90YWwgY29weSBudW1iZXIgb2Ygc2VnbWVudCBpbiBoZWFsdGh5IHRpc3N1ZS4gCiAgIyBGb3IgYXV0b3NvbWUgdGhpcyB3aWxsIGJlIHR3byBhbmQgbWFsZSBzZXggY2hyb21vc29tZXMgb25lLgogICMgU2VlOiBodHRwczovL2dpdGh1Yi5jb20vUm90aC1MYWIvcHljbG9uZS12aQogIG11dGF0ZShub3JtYWxfY24gPSBjYXNlX3doZW4oZ3JlcGwoImNoclkiLCBDaHJvbW9zb21lKSB+ICIxIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIjIiKSkgJT4lIAogIAogICMgQ2FsY3VsYXRlIENDRgogICMgQ0NGKCkgJT4lIAogICMgdXNpbmcgZm9ybXVsYSBmb3IgQ0NGIGNhbGN1bGF0aW9uCiAgbXV0YXRlKENDRiA9ICgyKnRfYWx0X2NvdW50KS8gKHRfcmVmX2NvdW50ICsgdF9hbHRfY291bnQpKSAjJT4lIAogICN3cml0ZV90c3YoZmlsZS5wYXRoKHNjcmF0Y2hfZGlyLCAibWFmX3BidGEudHN2IikpCgojIE51bWJlciBvZiBzYW1wbGVzIGluIHRoZSBgbWFmX2RmYAptYWZfc2FtcGxlcyA8LSBwcmludChsZW5ndGgodW5pcXVlKG1hZl9kZiRLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEKSkpCgojIFJlYWQgcGF0aWVudCBsaXN0Cmdlbm9taWNfcGFpcmVkX2RmIDwtIHJlYWRyOjpyZWFkX3RzdihnZW5vbWljX3BhaXJlZF9maWxlLCBndWVzc19tYXggPSAxMDAwMDAsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JSAKICBzZWxlY3QoIWMoY2FuY2VyX2dyb3VwLCBleHBlcmltZW50YWxfc3RyYXRlZ3kpKSAlPiUgCiAgbGVmdF9qb2luKG1hZl9kZiwgYnkgPSBjKCJLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEIikpICU+JSAjIGNyZWF0ZSB1bmlxdWUgaWRlbnRpZmllcnMKICBkcGx5cjo6bXV0YXRlKG11dGF0aW9uX2lkID0gcGFzdGUoS2lkc19GaXJzdF9QYXJ0aWNpcGFudF9JRCwgdHVtb3JfZGVzY3JpcHRvciwgS2lkc19GaXJzdF9CaW9zcGVjaW1lbl9JRCwgQ2hyb21vc29tZSwgU3RhcnRfUG9zaXRpb24sIFJlZmVyZW5jZV9BbGxlbGUsIFR1bW9yX1NlcV9BbGxlbGUyLCBzZXAgPSAiOiIpLAogICAgICAgICAgICAgICAgY2dfaWRfa2lkcyA9IHBhc3RlKGNnX2lkLCBLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lELCBzZXAgPSAiXyIpLAogICAgICAgICAgICAgICAgY2dfaWRfa2lkcyA9IHN0cl9yZXBsYWNlKGNnX2lkX2tpZHMsICIvfC0iLCAiXyIpLAogICAgICAgICAgICAgICAgY2dfaWRfa2lkcyA9IHN0cl9yZXBsYWNlX2FsbChjZ19pZF9raWRzLCAiICIsICJfIiksCiAgICAgICAgICAgICAgICBjZ19pZCA9IHN0cl9yZXBsYWNlKGNnX2lkLCAiL3wtIiwgIl8iKSwKICAgICAgICAgICAgICAgIGNnX2lkID0gc3RyX3JlcGxhY2VfYWxsKGNnX2lkLCAiICIsICJfIiksCiAgICAgICAgICAgICAgICBzYW1wbGVfaWQgPSBwYXN0ZSh0dW1vcl9kZXNjcmlwdG9yLCBLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lELCBzZXAgPSAiOiIpKSAjJT4lIAogICNmaWx0ZXIoIWlzLm5hKFZBRikgIywKICAgICAgICAgIyFWQUYgPT0gMCAjLCAKICAgICAgICAgIyFpcy5uYSh0bWIpCiAgICAgICAgIyApCgojIE51bWJlciBvZiBzYW1wbGVzIGluIHRoZSBgZ2Vub21pY19wYWlyZWRfZGZgCmdlbm9taWNfc2FtcGxlcyA8LSBwcmludChsZW5ndGgodW5pcXVlKGdlbm9taWNfcGFpcmVkX2RmJEtpZHNfRmlyc3RfUGFydGljaXBhbnRfSUQpKSkKCiMgTGV0J3MgY291bnQgI3NwZWNpbWVucyBwZXIgc2FtcGxlIAojIFdlIHdpbGwgcmVtb3ZlIGFueSBzYW1wbGVzIHdpdGggbGVzcyB0aGFuIDIgc3BlY2ltZW5zIGFzIHBoeWxvZ2VuaWVzIHJlcXVpcmUgYXQgbGVhc3QgMyB0YXhhCmtpZHNfc3BlY2ltZW5zX25fZGYgPC0gZ2Vub21pY19wYWlyZWRfZGYgJT4lIAogIHNlbGVjdChLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lELCBLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lELCB0dW1vcl9kZXNjcmlwdG9yKSAlPiUgCiAgdW5pcXVlKCkgJT4lIAogIGRwbHlyOjpjb3VudChLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEKSAlPiUgCiAgZHBseXI6Om11dGF0ZShraWRzX3NwZWNpbWVuc19uID0gZ2x1ZTo6Z2x1ZSgie0tpZHNfRmlyc3RfUGFydGljaXBhbnRfSUR9ICAoTj17bn0pIikpICU+JQogIGRwbHlyOjpyZW5hbWUoa2lkc19zcGVjaW1lbnNfbnVtYmVyID0gbikgJT4lIAogIGZpbHRlcigha2lkc19zcGVjaW1lbnNfbnVtYmVyIDw9IDIpICU+JQoKICBsZWZ0X2pvaW4oZ2Vub21pY19wYWlyZWRfZGYsIGJ5ID0gYygiS2lkc19GaXJzdF9QYXJ0aWNpcGFudF9JRCIpKSAlPiUKICAjbGVmdF9qb2luKG1hZl9kZikgJT4lIAogIGZpbHRlcighaXMubmEoQ2hyb21vc29tZSkpIAoKCiMgTGV0J3MgY29uZmlybSBhbmQgYWRkIHRoZSBudW1iZXIgb2YgdGltZXBvaW50cyBwZXIgc2FtcGxlCiMgSW4gY2FzZSB3ZSBsb3N0IGFueSBmcm9tIGZpbHRlcmluZyBoeXBlcm11dGFudHMgYW5kIGhpZ2ggcmVhZHMvYWx0ZXJhdGlvbgp0aW1lcG9pbnRzX25fZGYgPC0ga2lkc19zcGVjaW1lbnNfbl9kZiAlPiUgCiAgc2VsZWN0KEtpZHNfRmlyc3RfUGFydGljaXBhbnRfSUQsIHR1bW9yX2Rlc2NyaXB0b3IpICU+JSAKICB1bmlxdWUoKSAlPiUgCiAgZHBseXI6OmNvdW50KEtpZHNfRmlyc3RfUGFydGljaXBhbnRfSUQpICU+JSAKICBkcGx5cjo6bXV0YXRlKGtpZHNfdGltZXBvaW50c19uID0gZ2x1ZTo6Z2x1ZSgie0tpZHNfRmlyc3RfUGFydGljaXBhbnRfSUR9ICAoTj17bn0pIikpICU+JQogIGRwbHlyOjpyZW5hbWUoa2lkc190aW1lcG9pbnRzX251bWJlciA9IG4pICU+JSAKICBmaWx0ZXIoIWtpZHNfdGltZXBvaW50c19udW1iZXIgPD0gMSkKCmRmIDwtIHRpbWVwb2ludHNfbl9kZiAlPiUgCiAgbGVmdF9qb2luKGtpZHNfc3BlY2ltZW5zX25fZGYsIGJ5ID0gYygiS2lkc19GaXJzdF9QYXJ0aWNpcGFudF9JRCIpKSAlPiUgCiAgd3JpdGVfdHN2KGZpbGUucGF0aChyZXN1bHRzX2RpciwgInNhbXBsZXNfZWxpZ2libGVfZm9yX3BoeWxvZ2VueS50c3YiKSkKCiMgTnVtYmVyIG9mIHNhbXBsZXMgaW4gdGhlIGBnZW5vbWljX3BhaXJlZF9kZmAgd2l0aCA+IDMgYmlvc3BlY2ltZW5zIGFuZCA+MiB0aW1lcG9pbnRzCnNhbXBsZXNfd2l0aF8zYnMgPC0gcHJpbnQobGVuZ3RoKHVuaXF1ZShkZiRLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEKSkpCnNhbXBsZXNfd2l0aF8zYnMgPC0gcHJpbnQodW5pcXVlKGRmJEtpZHNfRmlyc3RfUGFydGljaXBhbnRfSUQpKQogIAojIExpc3Qgd2l0aCBzYW1wbGVzIGVsaWdpYmxlIGZvciBwaHlsb2dlbnkKIyBJIGFkZGVkIHRoZSBpbmZvcm1hdGlvbiBhYm91dCB0byB1c2UgZm9yIHBoeWxvZ2VuZXRpYyBpbmZlcmVuY2VzCmxpc3RfZGYgPC0gZGYgJT4lIAogIHNlbGVjdChLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEKSAlPiUgCiAgdW5pcXVlKCkgJT4lIAogIG11dGF0ZShzb21hdGljX2dlcm1saW5lX3BoeWxvZ2VueSA9IGNhc2Vfd2hlbihncmVwbCgiUFRfS1o1NlhISlR8UFRfS1RSSjhURlkiLCBLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEKSB+ICJ5ZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJub3RfeWV0IikpICU+JSAKICB3cml0ZV90c3YoZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCAic2FtcGxlc19lbGlnaWJsZV9mb3JfcGh5bG9nZW55X2xpc3QudHN2IikpCgojIFJlbW92ZSBsYXJnZSBmaWxlcwpybShnZW5vbWljX3BhaXJlZF9kZiwga2lkc19zcGVjaW1lbnNfbl9kZiwgdG1iX2RmKQoKYGBgCgojIyBBZGQgTmF1dGlsdXMgbG9jYXRpb24gZm9yIERlY2Vhc2VkIHNwZWNpbWVucwoKYGBge3IgYWRkLU5hdXRpbHVzLWxvY2F0aW9ufQpuYXV0aWx1c19kZWNfZGYgPC0gcmVhZF9leGNlbChuYXV0aWx1c19kZWNfZmlsZSkgJT4lIAogIHJpZ2h0X2pvaW4oZGYsIGJ5ID0gYygic2FtcGxlX2lkIiwgImFsaXF1b3RfaWQiLCAidHVtb3JfZGVzY3JpcHRvciIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKG11dGF0aW9uX2lkID0gcGFzdGUoS2lkc19GaXJzdF9QYXJ0aWNpcGFudF9JRCwgdHVtb3JfZGVzY3JpcHRvciwgS2lkc19GaXJzdF9CaW9zcGVjaW1lbl9JRCwgQ2hyb21vc29tZSwgU3RhcnRfUG9zaXRpb24sIFJlZmVyZW5jZV9BbGxlbGUsIFR1bW9yX1NlcV9BbGxlbGUyLCBzZXAgPSAiOiIpKSAlPiUgCiAgd3JpdGVfdHN2KGZpbGUucGF0aChyZXN1bHRzX2RpciwgIm5hdXRpbHVzX2RlYy50c3YiKSkKCmxpc3RfZGYgPC0gbmF1dGlsdXNfZGVjX2RmICU+JSAKICBzZWxlY3QoS2lkc19GaXJzdF9QYXJ0aWNpcGFudF9JRCwgS2lkc19GaXJzdF9CaW9zcGVjaW1lbl9JRCwgYE5vdGUgZmllbGQgZnJvbSBOYXV0aWx1cyBvZiBpbml0aWFsIHBhcmVudGApICU+JSAKICB1bmlxdWUoKSAlPiUgCiAgd3JpdGVfdHN2KGZpbGUucGF0aChyZXN1bHRzX2RpciwgIm5hdXRpbHVzX2RlY19saXN0LnRzdiIpKQoKYGBgCgojIyBPdGhlciwgbWF5YmUgdG8gZGVsZXRlCgpgYGAge3Igb3RoZXItdGhpbmdzfQoKIyBNYWtlIGxpc3Qgd2l0aCBzYW1wbGVzIHdpdGggPjIgYmlvc3BlY2ltZW5zIGF0IERlY2Vhc2VkIHRpbWVwb2ludApkZWNfbl9kZiA8LSBkZiAlPiUgCiAgZmlsdGVyKHR1bW9yX2Rlc2NyaXB0b3IgPT0gIkRlY2Vhc2VkIikgJT4lIAogIHNlbGVjdChLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lELCB0dW1vcl9kZXNjcmlwdG9yLCBLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lEKSAlPiUgCiAgdW5pcXVlKCkgJT4lIAogIGRwbHlyOjpjb3VudChLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEKSAlPiUgCiAjIGRwbHlyOjptdXRhdGUoa2lkc19kZWNfbiA9IGdsdWU6OmdsdWUoIntLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEfSAgKE49e259KSIpKSAlPiUKICBkcGx5cjo6cmVuYW1lKGtpZHNfZGVjZWFzZWRfYnNfbnVtYmVyID0gbikgJT4lIAogIGZpbHRlcigha2lkc19kZWNlYXNlZF9ic19udW1iZXIgPD0gMSkgJT4lIAogIHdyaXRlX3RzdihmaWxlLnBhdGgocmVzdWx0c19kaXIsICJraWRzX2RlY19tdWx0aXBsZV9ic19saXN0LnRzdiIpKQoKIyMjLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyBsZXQncyBsb29rIGludG8gUFRfM0tNOVc4UzgKI1BUXzNLTTlXOFM4X2RmIDwtIG5hdXRpbHVzX2RlY19kZiAlPiUgCiMgIGZpbHRlcihLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEID09ICJQVF8zS005VzhTOCIsCiAjICAgICAgICBLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lEID09ICJCU18yTlFYWTUyOCIpICU+JSAKIyAgc2VsZWN0KEtpZHNfRmlyc3RfUGFydGljaXBhbnRfSUQsIEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQsIGBOb3RlIGZpZWxkIGZyb20gTmF1dGlsdXMgb2YgaW5pdGlhbCBwYXJlbnRgKSAlPiUgCiMgIHVuaXF1ZSgpICU+JSAKIyAgd3JpdGVfdHN2KGZpbGUucGF0aChyZXN1bHRzX2RpciwgIm5hdXRpbHVzX2RlY19saXN0LnRzdiIpKQogIAojYnNfaWQgPC0gcHJpbnQodW5pcXVlKFBUXzNLTTlXOFM4X2RmJEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQpKQpgYGAKCgojIENyZWF0ZSBweWNsb25lIGlucHV0IGZpbGVzIAoKV2UgbmVlZCB0byBnZW5lcmF0ZSB0aGUgaW5wdXQgZmlsZXMgYWNjb3JkaW5nIHRvIHRoZSBtZXRob2QncyB0ZW1wbGF0ZS4gClBoeWxvZ2VuZXRpYyBtZXRob2RzIHJlcXVpcmUgYXQgbGVhc3QgMiBzYW1wbGVzIHBlciB0dW1vciBzaXRlIChtdWx0aXJlZ2lvbmFsIHNhbXBsaW5nIHBlciBhbmF0b21pY2FsIHNpdGUpLgpIZXJlLCB3ZSB3aWxsIGNvbnNpZGVyIGtpZHMgc2FtcGxlcyB3aXRoIG1vcmUgdGhhbiAyIHRpbWVwb2ludHMgd2l0aCBvbmUgb3IgbW9yZSBiaW9zcGVjaW1lbnMuIApXZSB3aWxsIGNvbXBhcmUgbGF0ZXIgZGlmZmVyZW5jZXMgaW4gc2FtcGxlcyB3aXRoIHNpbmdsZSB2cyBtdWx0aXBsZSBiaW9zcGVjaW1lbnMuCgpgYGB7ciBjcmVhdGUtcHljbG9uZS1hbGwtc2FtcGxlcy1kZn0KIyBDcmVhdGUgcHljbG9uZSBkZiBmb3IgYWxsIHNhbXBsZXMKcHljbG9uZV9hbGxfc2FtcGxlc19kZiA8LSBuYXV0aWx1c19kZWNfZGYgJT4lCiAgc2VsZWN0KEtpZHNfRmlyc3RfUGFydGljaXBhbnRfSUQsIEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQsIGNnX2lkLCAKICAgICAgICAgY2dfaWRfa2lkcywgbXV0YXRpb25faWQsIHNhbXBsZV9pZCwKICAgICAgICAgdHVtb3JfZGVzY3JpcHRvciwgQ2hyb21vc29tZSwgU3RhcnRfUG9zaXRpb24sIAogICAgICAgICBSZWZlcmVuY2VfQWxsZWxlLCBUdW1vcl9TZXFfQWxsZWxlMiwgdF9yZWZfY291bnQsIHRfYWx0X2NvdW50LAogICAgICAgICBub3JtYWxfY24sIHR1bW9yX2ZyYWN0aW9uLCBtdXRhdGlvbl9jb3VudCwgSHVnb19TeW1ib2wpICU+JSAKICAKICAjIGNoYW5nZSBuYW1lcyB0byBtYXRjaCBpbnB1dCByZXF1aXJlbWVudHMKICBkcGx5cjo6cmVuYW1lKCJyZWZfY291bnRzIiA9ICJ0X3JlZl9jb3VudCIsIAogICAgICAgICAgICAgICAgImFsdF9jb3VudHMiID0gInRfYWx0X2NvdW50IiwKICAgICAgICAgICAgICAgICJ0dW1vdXJfY29udGVudCIgPSAidHVtb3JfZnJhY3Rpb24iKSAKCnNhbXBsZXNfcHljbG9uZSA8LSBwcmludCh1bmlxdWUocHljbG9uZV9hbGxfc2FtcGxlc19kZiRLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEKSkKCiMgUmVtb3ZlIGxhcmdlIGZpbGVzCiMgcm0obmF1dGlsdXNfZGVjX2RmKQoKIyBJIHdpbGwgdGVzdCBvbmUgSEdHIGRhdGFzZXQgZm9yIG5vdwojIFBUX1o0QkYyTlNCCgojUFRfWjRCRjJOU0JfREYgPC0gcHljbG9uZV9hbGxfc2FtcGxlc19kZiAlPiUgCiMgIGZpbHRlcihLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEID09ICJQVF9aNEJGMk5TQiIpCiAgICAgICAgICAgICAgICAgICAKYGBgCgojIyBBZGQgbWFqb3JfY24sIG1pbm9yX2NuIGNvbHVtbnMgZnJvbSBjbnMgZmlsZXMKCmBgYHtyIHByb2Nlc3MtY25zLWZpbGVzfQpkYXRhX2RpciA8LSBkaXIocGF0aCA9IGNuc19kaXIsICBwYXR0ZXJuID0gIi5jYWxsLmNucyIsIGZ1bGwubmFtZXMgPSBUUlVFLCByZWN1cnNpdmUgPSBUUlVFKQoKIyBDcmVhdGUgbGlzdCAKZGF0YV9saXN0IDwtIGxpc3QoKQoKZm9yIChpIGluIDE6bGVuZ3RoKGRhdGFfZGlyKSApIHsgCiAgCiAgIyBDcmVhdGUgc2FtcGxlX25hbWUKICBzYW1wbGVfbmFtZSA8LSAgdW5pcXVlKGFzLmNoYXJhY3Rlcihnc3ViKCIuY2FsbC5jbnMiLCAiIiwgc3RyX3NwbGl0X2ZpeGVkKGRhdGFfZGlyW2ldLCAiLyIsIDEzKVssMTFdKSkpCiAgI3NhbXBsZV9uYW1lIDwtICB1bmlxdWUoYXMuY2hhcmFjdGVyKGdzdWIoIi5jYWxsLmNucyIsICIiLCBzdHJfc3BsaXRfZml4ZWQoZGF0YV9kaXJbaV0sICIvIiwgMTApWyw5XSkpKQogIHNhbXBsZV9uYW1lIDwtIHNvcnQoc2FtcGxlX25hbWUsIGRlY3JlYXNpbmcgPSBGQUxTRSkKICBwcmludChzYW1wbGVfbmFtZSkKICAKICBmb3IgKHggaW4gc2VxX2Fsb25nKHNhbXBsZV9uYW1lKSApIHsgCiAgICAKICAgIGRhdGFfbGlzdFtbaV1dIDwtIHJlYWQuY3N2KGRhdGFfZGlyW2ldLCBoZWFkZXI9VCwgc2VwPSJcdCIpIAogIAogICAgCiAgIyBDcmVhdGUgZmlsZV9uYW1lCiAgZmlsZV9uYW1lIDwtIGdzdWIoIi5jYWxsLmNucyIsICIiLCBzdHJfc3BsaXRfZml4ZWQoZGF0YV9kaXJbaV0sICIvIiwgMTMpWywxMl0pCiAgcHJpbnQoZmlsZV9uYW1lKQogIAogIGRhdGFfbGlzdFtbaV1dIDwtIGRhdGFfbGlzdFtbaV1dICU+JSAKICAgIG11dGF0ZShLaWRzX0ZpcnN0X0Jpb3NwZWNpbWVuX0lEID0gZmlsZV9uYW1lKQogIAogICMgVGhlIGZvbGxvd2luZyBjb2RlIGFzc2lnbnMgbmFtZSB0byBkZgogICMgQnV0IGFkZHMgYW4gZXh0cmEgZGYgaW50byB0aGUgbGlzdCAtIGRvbnQga25vdyB5ZXQgd2h5IGJ1dCBsZXQncyByZW1vdmUsIGl0J3Mgbm90IG5lY2Vzc2FyeQogICNkZiA8LSBhc3NpZ24oZmlsZV9uYW1lLCBkYXRhX2xpc3QpIAogICNkYXRhX2xpc3RbW2ZpbGVfbmFtZV1dIDwtIGRmCiAgfQp9CgojIEJpbmQgYWxsIGRmIGZyb20gbGlzdCAKZGF0YV9saXN0X2JpbmQgPC0gZHBseXI6OmJpbmRfcm93cyhkYXRhX2xpc3QpIAoKIyBSZW1vdmUgbGFyZ2UgZmlsZXMKcm0oZGF0YV9saXN0KQoKIyBDcmVhdGUgYW5kIHNhdmUgcHljbG9uZV9pbnB1dCEKcHljbG9uZV9pbnB1dCA8LSBkYXRhX2xpc3RfYmluZCAlPiUgCiAgCiAgIyBSZW5hbWUgdG8gbWF0Y2ggaW5wdXQgZm9ybWF0CiAgIyBUbyBmaWd1cmUgb3V0IGlmIHRoZSBhc3NpZ25tZW50IGlzIGNvcnJlY3QKICBkcGx5cjo6cmVuYW1lKCJtYWpvcl9jbiIgPSAiY24xIiwgCiAgICAgICAgICAgICAgICAibWlub3JfY24iID0gImNuMiIpICU+JSAKCiAgbGVmdF9qb2luKHB5Y2xvbmVfYWxsX3NhbXBsZXNfZGYpICU+JSAKICAKICBmaWx0ZXIoIWlzLm5hKG1ham9yX2NuKSwKICAgICAgICAgIWlzLm5hKG1pbm9yX2NuKSkgJT4lCiAgI2RwbHlyOjptdXRhdGUobXV0YXRpb25faWQgPSBwYXN0ZShtdXRhdGlvbl9pZCwgbWFqb3JfY24sIG1pbm9yX2NuLCByZWZfY291bnRzLCBhbHRfY291bnRzLCBzZXAgPSAiOiIpKSAlPiUgCiAgZHBseXI6Om11dGF0ZShtdXRhdGlvbl9pZCA9IHBhc3RlKEtpZHNfRmlyc3RfUGFydGljaXBhbnRfSUQsIHR1bW9yX2Rlc2NyaXB0b3IsIEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQsIENocm9tb3NvbWUsIFN0YXJ0X1Bvc2l0aW9uLCBSZWZlcmVuY2VfQWxsZWxlLCBUdW1vcl9TZXFfQWxsZWxlMiwgc2VwID0gIjoiKSkgJT4lIAogIHNlbGVjdChLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lELCB0dW1vcl9kZXNjcmlwdG9yLCBjZ19pZF9raWRzLCBtdXRhdGlvbl9pZCwgc2FtcGxlX2lkLCByZWZfY291bnRzLCAKICAgICAgICAgYWx0X2NvdW50cywgbm9ybWFsX2NuLCBtYWpvcl9jbiwgbWlub3JfY24sIHR1bW91cl9jb250ZW50LCBtdXRhdGlvbl9jb3VudCwgSHVnb19TeW1ib2wpICU+JSAKICAKICAjIFRvIGVuc3VyZSB0aGVyZSBhcmUgbm8gZHVwbGljYXRlZCBlbnRyaWVzIGluIHRoZSBkYXRhZnJhbWUKICBkaXN0aW5jdCgpICU+JSAKICBmaWx0ZXIoIWlzLm5hKEtpZHNfRmlyc3RfUGFydGljaXBhbnRfSUQpKSAKCiMgU2F2ZSBkZiB3aXRoIGFsbCBkYXRhIHRvZ2V0aGVyCiMgV2Ugd2lsbCBuZWVkIHRoaXMgdG8gcHJlcGFyZSB0aGUgaW5wdXQgZmllbCBmb3IgQ2xvbkV2b2wKcHljbG9uZV9pbnB1dF9hbGwgPC0gbmF1dGlsdXNfZGVjX2RmICU+JQogIHNlbGVjdChtdXRhdGlvbl9pZCwgVkFGLCBDQ0YsIGdlbmVfcHJvdGVpbiwgSHVnb19TeW1ib2wpICU+JSAKICByaWdodF9qb2luKHB5Y2xvbmVfaW5wdXQpICU+JSAKICB3cml0ZV90c3YoZmlsZS5wYXRoKHJlc3VsdHNfZGlyLCAicHljbG9uZV9pbnB1dF9hbGxfZGF0YS50c3YiKSkKCgpzYW1wbGVzX3B5Y2xvbmUgPC0gcHJpbnQodW5pcXVlKHB5Y2xvbmVfaW5wdXQkS2lkc19GaXJzdF9QYXJ0aWNpcGFudF9JRCkpCgoKIyBUbyBmaW5kIHRoZSBwb3NpdGlvbiBvZiBkdXBsaWNhdGUgZWxlbWVudHMgaW4geCwgdXNlIHRoaXM6CiMgZHVwbGljYXRlZChweWNsb25lX2lucHV0KQoKIyBFeHRyYWN0IGR1cGxpY2F0ZSBlbGVtZW50czoKIyBweWNsb25lX2lucHV0W2R1cGxpY2F0ZWQocHljbG9uZV9pbnB1dCldCgpgYGAKCiMgU2F2ZSBpbnB1dCBmaWxlcwoKYGBge3Igc2F2ZS1pbnB1dC1maWxlc30KZm9yIChpIGluIDE6bGVuZ3RoKGRhdGFfZGlyKSApIHsgCiAgCiAgIyBDcmVhdGUgc2FtcGxlX25hbWUKICBzYW1wbGVfbmFtZSA8LSAgdW5pcXVlKGFzLmNoYXJhY3Rlcihnc3ViKCIuY2FsbC5jbnMiLCAiIiwgc3RyX3NwbGl0X2ZpeGVkKGRhdGFfZGlyW2ldLCAiLyIsIDEzKVssMTFdKSkpCiAgI3NhbXBsZV9uYW1lIDwtICB1bmlxdWUoYXMuY2hhcmFjdGVyKGdzdWIoIi5jYWxsLmNucyIsICIiLCBzdHJfc3BsaXRfZml4ZWQoZGF0YV9kaXJbaV0sICIvIiwgMTApWyw5XSkpKQogIHNhbXBsZV9uYW1lIDwtIHNvcnQoc2FtcGxlX25hbWUsIGRlY3JlYXNpbmcgPSBGQUxTRSkKICBwcmludChzYW1wbGVfbmFtZSkKICAKZm9yICh4IGluIHNlcV9hbG9uZyhzYW1wbGVfbmFtZSkgKSB7IAogIAogICMgU2F2ZSBpbnB1dCBmaWxlIGZvciBweWNsb25lLXZpCiAgcHljbG9uZV9mbmFtZSA8LSBwYXN0ZTAocHljbG9uZXZpX2lucHV0X2RpciwgIi8iLCBzYW1wbGVfbmFtZVt4XSwgIi50c3YiKQogIHByaW50KHB5Y2xvbmVfZm5hbWUpCiAgCiAgcHljbG9uZV9pbnB1dF9zdWJzZXQgPC0gcHljbG9uZV9pbnB1dCAlPiUKICAgIGZpbHRlcihLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEID09IHNhbXBsZV9uYW1lW3hdKSAlPiUgCiAgICAjc2VsZWN0KC1jKEtpZHNfRmlyc3RfUGFydGljaXBhbnRfSUQpKSAlPiUgCiAgd3JpdGVfdHN2KGZpbGUucGF0aChweWNsb25lX2ZuYW1lKSkKICAKICAKICAjIFNhdmUgaW5wdXQgZmlsZSBmb3IgRmFzdENsb25lCiAgZmFzdGNsb25lX2ZuYW1lIDwtIHBhc3RlMChmYXN0Y2xvbmVfaW5wdXRfZGlyLCAiLyIsIHNhbXBsZV9uYW1lW3hdLCAiLnRzdiIpCiAgcHJpbnQoZmFzdGNsb25lX2ZuYW1lKQogIAogIGZhc3RjbG9uZV9pbnB1dF9zdWJzZXQgPC0gcHljbG9uZV9pbnB1dCAlPiUKICAgIGRwbHlyOjpyZW5hbWUoInZhcl9jb3VudHMiID0gImFsdF9jb3VudHMiKSAlPiUgCiAgICBmaWx0ZXIoS2lkc19GaXJzdF9QYXJ0aWNpcGFudF9JRCA9PSBzYW1wbGVfbmFtZVt4XSkgJT4lIAogICAgI3NlbGVjdCgtYyhLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEKSkgJT4lIAogIHdyaXRlX3RzdihmaWxlLnBhdGgoZmFzdGNsb25lX2ZuYW1lKSkKICAKICB9Cn0KCmBgYAoKIyBQbG90IGRlcHRoIGNvdmVyYWdlCgpgYGB7ciBkZWZpbmUtcGFyYW1ldGVycy1mb3ItcGxvdHN9CiMgUmVhZCBjb2xvciBwYWxldHRlCnBhbGV0dGVfZGYgPC0gcmVhZHI6OnJlYWRfdHN2KHBhbGV0dGVfZmlsZSwgZ3Vlc3NfbWF4ID0gMTAwMDAwLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUgCiAgbXV0YXRlKHR1bW9yX2Rlc2NyaXB0b3IgPSBjb2xvcl9uYW1lcykKCiMgRGVmaW5lIGFuZCBvcmRlciBwYWxldHRlCnBhbGV0dGUgPC0gcGFsZXR0ZV9kZiRoZXhfY29kZXMKbmFtZXMocGFsZXR0ZSkgPC0gcGFsZXR0ZV9kZiR0dW1vcl9kZXNjcmlwdG9yCgojIERlZmluZSB0aW1lcG9pbnRzCnRpbWVwb2ludHMgPSBjKCJEaWFnbm9zaXMiLCAiUHJvZ3Jlc3NpdmUiLCAiUmVjdXJyZW5jZSIsICJEZWNlYXNlZCIsICJTZWNvbmQgTWFsaWduYW5jeSIsICJVbmF2YWlsYWJsZSIpCgpgYGAKCmBgYCB7ciBkZXB0aC1jb3ZlcmFnZSwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodCA9IDUsIGZpZy5mdWxsd2lkdGggPSBUUlVFfQpmb3IgKGkgaW4gMTpsZW5ndGgoZGF0YV9kaXIpICkgeyAKICAKICAjIENyZWF0ZSBzYW1wbGVfbmFtZQogIHNhbXBsZV9uYW1lIDwtICB1bmlxdWUoYXMuY2hhcmFjdGVyKGdzdWIoIi5jYWxsLmNucyIsICIiLCBzdHJfc3BsaXRfZml4ZWQoZGF0YV9kaXJbaV0sICIvIiwgMTMpWywxMV0pKSkKICBzYW1wbGVfbmFtZSA8LSBzb3J0KHNhbXBsZV9uYW1lLCBkZWNyZWFzaW5nID0gRkFMU0UpCiAgcHJpbnQoc2FtcGxlX25hbWUpCiAgCmZvciAoeCBpbiBzZXFfYWxvbmcoc2FtcGxlX25hbWUpICkgeyAKICAKICBweWNsb25lX2lucHV0X3N1YnNldCA8LSBweWNsb25lX2lucHV0ICU+JQogICAgZmlsdGVyKEtpZHNfRmlyc3RfUGFydGljaXBhbnRfSUQgPT0gc2FtcGxlX25hbWVbeF0pICU+JSAKICAgIHNlbGVjdCgtYyhLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEKSkgIyU+JSAKICAgIyBtdXRhdGUodHVtb3JfZGVzY3JpcHRvciA9IGZhY3Rvcih0dW1vcl9kZXNjcmlwdG9yKSwKICAgICMgICAgIHR1bW9yX2Rlc2NyaXB0b3IgPSBmY3RfcmVsZXZlbCh0dW1vcl9kZXNjcmlwdG9yLCB0aW1lcG9pbnRzKSkgJT4lIAogICAgI2FycmFuZ2UodHVtb3JfZGVzY3JpcHRvciwgc2FtcGxlX2lkKQogIAogICMgTWFrZSB0aGlzIHJlcHJvZHVjaWJsZQogIHNldC5zZWVkKDIwMjMpCgogICMgRGVmaW5lIGxhYmVsIGZvciBwbG90cwogIFRpbWVwb2ludCA8LSBmYWN0b3IoeCA9IHB5Y2xvbmVfaW5wdXRfc3Vic2V0JHR1bW9yX2Rlc2NyaXB0b3IsIGxldmVscyA9IHRpbWVwb2ludHMpCiAgCiAgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKICAjIENyZWF0ZSBieHAgcmVmX2NvdW50cwogICAgcCA8LSBwcmludChnZ3Bsb3QocHljbG9uZV9pbnB1dF9zdWJzZXQsIGFlcyhzYW1wbGVfaWQsIHJlZl9jb3VudHMsIGNvbG9yID0gVGltZXBvaW50KSkgKyAKICAgICAgICAgICAgICAgICBnZW9tX2ppdHRlcih3aWR0aCA9IDAuMTUsIHNpemUgPSAwLjcsIGFscGhhID0gMC42KSArCiAgICAgICAgICAgICAgICAgZ2dwbG90Mjo6Z2VvbV9ib3hwbG90KGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuMjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29lZiA9IDApICsgIyByZW1vdmUgd2hpc2tlcnMKICAgICAgICAgICAgICAgICB0aGVtZV9QdWJsaWNhdGlvbigpICsgCiAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNvcnQobmFtZXMocGFsZXR0ZSkpKSArCiAgICAgICAgICAgICAgICAgI3JvdGF0ZSgpICsKICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKwogICAgICAgICAgICAgICAgIHN0YXRfc3VtbWFyeShmdW4ueT1tZWFuLHNoYXBlPTEsY29sPSdibGFjaycsZ2VvbT0ncG9pbnQnKSArCiAgICAgICAgICAgICAgICAgbGFicyh0aXRsZSA9IHNhbXBsZV9uYW1lW3hdLAogICAgICAgICAgICAgICAgICAgICAgeCA9ICJzYW1wbGVfaWQiLAogICAgICAgICAgICAgICAgICAgICAgeSA9ICJyZWZfY291bnRzIiwKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIlRpbWVwb2ludCIpKQogICAgCiAgICAjIFNhdmUgdGhlIHBsb3QKICAgIGdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMChzYW1wbGVfbmFtZVt4XSwgIi1yZWZfY291bnRzLnBkZiIpLCAKICAgICAgICAgcGF0aCA9IHB5Y2xvbmVfcGxvdHNfZGlyLCAKICAgICAgICAgd2lkdGggPSA2LCAKICAgICAgICAgaGVpZ2h0ID0gNSwgCiAgICAgICAgIGRldmljZSA9ICJwZGYiLCAKICAgICAgICB1c2VEaW5nYmF0cyA9IEZBTFNFKQogICAgCgogICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiAgIyBDcmVhdGUgYnhwIGFsdF9jb3VudHMKICAgIHAgPC0gcHJpbnQoZ2dwbG90KHB5Y2xvbmVfaW5wdXRfc3Vic2V0LCBhZXMoc2FtcGxlX2lkLCBhbHRfY291bnRzLCBjb2xvciA9IFRpbWVwb2ludCkpICsgCiAgICAgICAgICAgICAgICAgZ2VvbV9qaXR0ZXIod2lkdGggPSAwLjE1LCBzaXplID0gMC43LCBhbHBoYSA9IDAuNikgKwogICAgICAgICAgICAgICAgIGdncGxvdDI6Omdlb21fYm94cGxvdChjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAwLjI1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZWYgPSAwKSArICMgcmVtb3ZlIHdoaXNrZXJzCiAgICAgICAgICAgICAgICAgdGhlbWVfUHVibGljYXRpb24oKSArIAogICAgICAgICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzb3J0KG5hbWVzKHBhbGV0dGUpKSkgKwogICAgICAgICAgICAgICAgICNyb3RhdGUoKSArCiAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsKICAgICAgICAgICAgICAgICBzdGF0X3N1bW1hcnkoZnVuLnk9bWVhbixzaGFwZT0xLGNvbD0nYmxhY2snLGdlb209J3BvaW50JykgKwogICAgICAgICAgICAgICAgIGxhYnModGl0bGUgPSBzYW1wbGVfbmFtZVt4XSwKICAgICAgICAgICAgICAgICAgICAgIHggPSAic2FtcGxlX2lkIiwKICAgICAgICAgICAgICAgICAgICAgIHkgPSAiYWx0X2NvdW50cyIsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJUaW1lcG9pbnQiKSkKICAgIAogICAgIyBTYXZlIHRoZSBwbG90CiAgICBnZ3NhdmUoZmlsZW5hbWUgPSBwYXN0ZTAoc2FtcGxlX25hbWVbeF0sICItYWx0X2NvdW50cy5wZGYiKSwgCiAgICAgICAgIHBhdGggPSBweWNsb25lX3Bsb3RzX2RpciwgCiAgICAgICAgIHdpZHRoID0gNiwgCiAgICAgICAgIGhlaWdodCA9IDUsIAogICAgICAgICBkZXZpY2UgPSAicGRmIiwgCiAgICAgICAgdXNlRGluZ2JhdHMgPSBGQUxTRSkKICAKICAKfQp9CgpgYGAKCgojIFRvdGFsIG51bWJlciBvZiBtdXRhdGlvbnMgYWNyb3NzIHRpbWVwb2ludHMgYW5kIGJpb3NwZWNpbWVuIHNhbXBsZSBwZXIgUGF0aWVudCBjYXNlCgpgYGB7ciBjcmVhdGUtYmFycGxvdC1zYW1wbGUsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQgPSA1LCBmaWcuZnVsbHdpZHRoID0gVFJVRX0KZm9yIChpIGluIDE6bGVuZ3RoKGRhdGFfZGlyKSApIHsgCiAgCiAgIyBDcmVhdGUgc2FtcGxlX25hbWUKICBzYW1wbGVfbmFtZSA8LSAgdW5pcXVlKGFzLmNoYXJhY3Rlcihnc3ViKCIuY2FsbC5jbnMiLCAiIiwgc3RyX3NwbGl0X2ZpeGVkKGRhdGFfZGlyW2ldLCAiLyIsIDEzKVssMTFdKSkpCiAgc2FtcGxlX25hbWUgPC0gc29ydChzYW1wbGVfbmFtZSwgZGVjcmVhc2luZyA9IEZBTFNFKQogIHByaW50KHNhbXBsZV9uYW1lKQogIApmb3IgKHggaW4gc2VxX2Fsb25nKHNhbXBsZV9uYW1lKSApIHsgCiAgCiAgcHljbG9uZV9pbnB1dF9zdWJzZXQgPC0gcHljbG9uZV9pbnB1dCAlPiUKICAgIGZpbHRlcihLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEID09IHNhbXBsZV9uYW1lW3hdKSAlPiUgCiAgICBzZWxlY3QoLWMoS2lkc19GaXJzdF9QYXJ0aWNpcGFudF9JRCkpCiAgCiAgIyBEZWZpbmUgcGFyYW1ldGVycyBmb3IgZnVuY3Rpb24KICB5bGltID0gbWF4KHB5Y2xvbmVfaW5wdXRfc3Vic2V0JG11dGF0aW9uX2NvdW50KQogIAogIAogICAjIFJlbmFtZSBsZWdlbmQgZm9yIHRpbWVwb2ludHMKICBUaW1lcG9pbnQgPC0gZmFjdG9yKHB5Y2xvbmVfaW5wdXRfc3Vic2V0JHR1bW9yX2Rlc2NyaXB0b3IpCiAgCiAgIyBQbG90IHN0YWNrZWQgYmFycGxvdCAKICBwcmludChnZ3Bsb3QocHljbG9uZV9pbnB1dF9zdWJzZXQsIGFlcyh4ID0gc2FtcGxlX2lkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBtdXRhdGlvbl9jb3VudCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gVGltZXBvaW50KSkgKyAgCiAgICAgICAgICAgICAgIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2socmV2ZXJzZSA9IFRSVUUpKSArCiAgICAgICAgICAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuNSkgKyAKICAgICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSwgYnJlYWtzID0gc29ydChuYW1lcyhwYWxldHRlKSkpICsgCiAgICAgICAgICAgICAgIHRoZW1lX1B1YmxpY2F0aW9uKCkgKyAKICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA4NSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMSkpICsgCiAgICAgICAgICAgICAgIGxhYnModGl0bGUgPSBwYXN0ZShzYW1wbGVfbmFtZSkpICsgCiAgICAgICAgICAgICAgIGxhYnMoeCA9ICJzYW1wbGVfaWQiLCB5ID0gIlRvdGFsIE11dGF0aW9ucyIpICsKICAgICAgICAgICAgICAgeWxpbSgwLCB5bGltKSkgCiAgCiAgCn0KfQpgYGAKCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoKCg==